package com.qingyun.pdfservice.service.impl;

import com.qingyun.common.dto.Result;
import com.qingyun.pdfservice.client.FeedbackClient;
import com.qingyun.pdfservice.client.ScheduleClient;
import com.qingyun.pdfservice.client.StudentClient;
import com.qingyun.pdfservice.client.UserClient;
import com.qingyun.pdfservice.entity.*;
import com.qingyun.pdfservice.mapper.CourseMapper;
import com.qingyun.pdfservice.mapper.FeedbackPhotoMapper;
import com.qingyun.pdfservice.service.IPdfService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.stream.MapRecord;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.xhtmlrenderer.pdf.ITextRenderer;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import com.lowagie.text.pdf.BaseFont;

import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.ArrayList;

import static com.qingyun.common.util.RedisConstants.FIELD_FEEDBACK_ID;
import static com.qingyun.common.util.RedisConstants.PDF_TASK_QUEUE;


@Slf4j
@Service
public class PdfServiceImpl implements IPdfService {

    @Autowired
    private TemplateEngine templateEngine;

    @Autowired
    private FeedbackClient feedbackClient;
    @Autowired
    private FeedbackPhotoMapper feedbackPhotoMapper;
    @Autowired
    private ScheduleClient scheduleClient;
    @Autowired
    private CourseMapper courseMapper;
    @Autowired
    private UserClient userClient;
    @Autowired
    private StudentClient studentClient;

    @Value("${file.upload.base-path:D:/QingYunEduSystem/pdf-service/uploads/}")
    private String baseUploadPath;

    @Autowired(required = false)
    private StringRedisTemplate stringRedisTemplate;

    private static final String TEMPLATE_NAME = "feedback-template";

    // removed legacy byte[]/file output methods; keep ID-based API only

    @Override
    public Result generateFeedbackPdfById(Long feedbackId) {
        try {
            // 获取反馈信息
            Feedback feedback = feedbackClient.queryFeedbackById(feedbackId);
            if (feedback == null) {
                return Result.fail("反馈信息不存在");
            }
            //图片所存储位置的URL地址（URL数据存在feedback_photo表中）
            List<String> photos = getFeedbackPhotos(feedbackId);

            // 组装HTML模板所需信息
            String courseName = null; //从tb_feedback中的course_text中获取
            String teacherName = null; //从tb_user中获取
            String teachDateStr = null; //从tb_feedback中获取
            String startTimeStr = null; //从tb_feedback中获取
            String endTimeStr = null; //从tb_feedback中获取
            String studentName = null; //从tb_student中获取

            // 教师姓名
            if (feedback.getTeacherId() != null) {
                User teacher = userClient.getById(feedback.getTeacherId());
                teacherName = teacher != null ? teacher.getNickName() : null;
            }

            // 课程/日期
            if (feedback.getScheduleId() != null) {
                Schedule schedule = scheduleClient.byId(feedback.getScheduleId());
                if (schedule != null) {
                    teachDateStr = schedule.getTeachDate() != null ? schedule.getTeachDate().toString() : null;
                    startTimeStr = schedule.getStartTime() != null ? schedule.getStartTime().toString() : null;
                    endTimeStr = schedule.getEndTime() != null ? schedule.getEndTime().toString() : null;
                    if (schedule.getStudentId() != null) {
                        Student s = studentClient.queryStudentById(schedule.getStudentId());
                        if (s != null) { studentName = s.getName(); }
                    }
                    if (schedule.getCourseId() != null) {
                        Course course = courseMapper.selectById(schedule.getCourseId());
                        if (course != null) {
                            courseName = course.getName();
                        }
                    }
                }
            }

            if (courseName == null || courseName.trim().isEmpty()) {
                courseName = feedback.getCourseText();
            }

            // 构建一个视图对象（Map）注入模板，包含模板需要的字段
            // 因为HTML转PDF的插件传输对象是Hash_Map
            java.util.Map<String, Object> feedbackView = new java.util.HashMap<>();
            feedbackView.put("id", feedback.getId());
            feedbackView.put("content", feedback.getContent());
            feedbackView.put("createTime", feedback.getCreateTime());
            feedbackView.put("courseName", courseName);
            feedbackView.put("teachDate", teachDateStr);
            feedbackView.put("teacherName", teacherName);
            feedbackView.put("startTime", startTimeStr);
            feedbackView.put("endTime", endTimeStr);
            feedbackView.put("studentName", studentName);
            feedbackView.put("courseText", feedback.getCourseText());

            // 渲染模板 -> HTML
            Context context = new Context();
            context.setVariable("feedback", feedbackView);
            context.setVariable("photos", photos);
            context.setVariable("currentTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss")));

            //实现HTML- >PDF
            String htmlContent = templateEngine.process(TEMPLATE_NAME, context);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ITextRenderer renderer = new ITextRenderer();
            // 注册中文字体，避免中文不显示（下载接口路径也需要注册）
            try {
                ITextFontResolver fontResolver = renderer.getFontResolver();
                String[][] fonts = new String[][]{
                        {"C:/Windows/Fonts/msyh.ttc,0", "msyh.ttc(0)"},
                        {"C:/Windows/Fonts/msyh.ttc,1", "msyh.ttc(1)"},
                        {"C:/Windows/Fonts/msyh.ttf", "msyh.ttf"},
                        {"C:/Windows/Fonts/simsun.ttc,0", "simsun.ttc(0)"},
                        {"C:/Windows/Fonts/simhei.ttf", "simhei.ttf"}
                };
                for (String[] f : fonts) {
                    try {
                        String path = f[0];
                        String realPath = path.split(",")[0];
                        java.nio.file.Path fp = java.nio.file.Paths.get(realPath);
                        if (java.nio.file.Files.exists(fp)) {
                            fontResolver.addFont(path, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
                            log.info("PDF font registered: {}", path);
                        } else {
                            log.info("PDF font not found: {}", path);
                        }
                    } catch (Exception e) {
                        log.warn("PDF font register failed: {}", f[0]);
                    }
                }
            } catch (Exception e) {
                log.warn("PDF font register block failed: {}", e.getMessage());
            }
            // 让相对路径可被解析（主要用于图片 file:///）
            try {
                String base = baseUploadPath;
                if (!base.endsWith("/") && !base.endsWith("\\")) { base = base + "/"; }
                String baseUrl = "file:///" + base.replace("\\", "/");
                renderer.setDocumentFromString(htmlContent, baseUrl);
            } catch (Exception e) {
                renderer.setDocumentFromString(htmlContent);
            }
            renderer.layout();
            renderer.createPDF(outputStream);

            byte[] pdfBytes = outputStream.toByteArray();

            return Result.ok(pdfBytes);
        } catch (Exception e) {
            log.error("根据ID生成PDF失败", e);
            return Result.fail("PDF生成失败: " + e.getMessage());
        }
    }

    @Override
    public Result generateAndSaveFeedbackPdf(Long feedbackId) {
        try {
            Result r = generateFeedbackPdfById(feedbackId);
            if (!Boolean.TRUE.equals(r.getSuccess()) || r.getData() == null) {
                return r;
            }
            byte[] bytes = (byte[]) r.getData();

            Path pdfDir = Path.of(baseUploadPath, "pdf");
            Files.createDirectories(pdfDir);
            Path target = pdfDir.resolve("feedback_" + feedbackId + ".pdf");
            Path tmp = pdfDir.resolve("feedback_" + feedbackId + ".pdf.tmp");

            Files.write(tmp, bytes);
            Files.move(tmp, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
            return Result.ok(target.toString());
        } catch (Exception e) {
            log.error("生成并落盘PDF失败", e);
            return Result.fail("生成并落盘PDF失败: " + e.getMessage());
        }
    }

    @Override
    public String getBaseUploadPath() {
        return baseUploadPath;
    }

    @Override
    public Result submitPdfTask(Long feedbackId) {
        try {
            Path target = Path.of(baseUploadPath, "pdf", "feedback_" + feedbackId + ".pdf");
            if (Files.exists(target)) {
                java.util.Map<String, Object> data = new java.util.HashMap<>();
                data.put("status", "COMPLETED");
                data.put("filePath", target.toString());
                return Result.ok(data);
            }
            // 入队 Redis Stream（使用 PDF_TASK_QUEUE 作为Stream Key）
            if (stringRedisTemplate != null) {
                MapRecord<String, String, String> record = MapRecord.create(
                        PDF_TASK_QUEUE,
                        java.util.Map.of(FIELD_FEEDBACK_ID, String.valueOf(feedbackId))
                );
                stringRedisTemplate.opsForStream().add(record);
            }
            java.util.Map<String, Object> data = new java.util.HashMap<>();
            data.put("status", "PROCESSING");
            return Result.ok(data);
        } catch (Exception e) {
            return Result.fail(e.getMessage());
        }
    }

    /**
     * 获取反馈图片列表
     * 这里需要根据实际的数据结构来实现
     */
    private List<String> getFeedbackPhotos(Long feedbackId) {
        // 从图片表查询图片记录（主要获取图片的URL地址）
        List<FeedbackPhoto> photos = feedbackPhotoMapper.selectByFeedbackId(feedbackId);
        if (photos == null || photos.isEmpty()) {
            return new ArrayList<>();
        }
        // 将数据库中的相对URL转换为本地文件URL（Flying Saucer 需要可访问的本地路径或绝对URL）
        List<String> fileUrlList = new ArrayList<>(photos.size());
        for (FeedbackPhoto photo : photos) {
            String url = photo.getUrl();
            if (url == null || url.trim().isEmpty()) {
                continue;
            }
            // 期望的url形如：/uploads/feedback/images/xxx.png
            // 我们需要映射成本地磁盘路径：{baseUploadPath}/feedback/images/xxx.png
            String normalizedBase = baseUploadPath;
            if (!normalizedBase.endsWith("/") && !normalizedBase.endsWith("\\")) {
                normalizedBase = normalizedBase + "/";
            }

            String fileSystemPath;
            if (url.startsWith("/uploads/")) {
                // 去掉前导的 /uploads/ 前缀，拼到物理上传目录
                String relative = url.substring("/uploads/".length());
                fileSystemPath = normalizedBase + relative.replace("/", "/");
            } else {
                // 已经是文件名或其它相对形式，直接拼接
                fileSystemPath = normalizedBase + url.replace("/", "/");
            }

            // 转换为 file:// URL，替换为正斜杠
            String fileUrl = "file:///" + fileSystemPath.replace("\\", "/");
            fileUrlList.add(fileUrl);
        }

        return fileUrlList;
    }
}
